package com.beiding.workordersystem.common.config;

import com.beiding.workordersystem.common.standard.R;
import com.beiding.workordersystem.common.utils.MySecurityUtils;
import com.beiding.workordersystem.system.entity.AccountEntity;
import com.beiding.workordersystem.system.entity.AuthorityEntity;
import com.beiding.workordersystem.system.entity.RoleEntity;
import com.beiding.workordersystem.system.entity.UserEntity;
import com.beiding.workordersystem.system.model.MyCredentials;
import com.beiding.workordersystem.system.service.AccountService;
import com.beiding.workordersystem.system.service.ConfigPropertyService;
import com.beiding.workordersystem.system.service.UserService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter implements InitializingBean {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private AccountService accountService;

    @Autowired
    private UserService userService;

    @Autowired
    private ConfigPropertyService configPropertyService;

    private ObjectMapper objectMapper = new ObjectMapper();


    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.formLogin().disable();
        http.logout().logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.ok("成功退出")));
        });

        http.addFilterAt((servletRequest, servletResponse, filterChain) -> {
            HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
            if (httpServletRequest.getRequestURI().equals("/login")) {

                HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
                try {

                    AccountEntity accountEntity = objectMapper.readValue(httpServletRequest.getInputStream(), AccountEntity.class);
                    AccountEntity user = accountService.loadUserByUsername(accountEntity.getUsername());
                    if (user == null) {
                        httpServletResponse.setStatus(HttpStatus.OK.value());
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.unauthorized("用户名密码错误")));
                        return;
                    }

                    if (accountEntity.getPassword() == null || !passwordEncoder().matches(accountEntity.getPassword(), user.getPassword())) {
                        httpServletResponse.setStatus(HttpStatus.OK.value());
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.unauthorized("用户名密码错误")));
                        return;
                    }

                    Set<GrantedAuthority> grantedAuthorities = new HashSet<>();

                    MyCredentials myCredentials = new MyCredentials();
                    myCredentials.setUsername(user.getUsername());
                    myCredentials.setRoleEntities(user.getRoleEntities());
                    myCredentials.setRoles(user.getRoleEntities().stream().map(RoleEntity::getRole).collect(Collectors.toSet()));
                    Set<AuthorityEntity> authorityEntities = new HashSet<>();
                    Set<String> as = new HashSet<>();
                    user.getRoleEntities().forEach(o->{
                        o.getAuthorities().forEach(a->{
                            authorityEntities.add(a);
                            as.add(a.getAuthority());
                            grantedAuthorities.add(new SimpleGrantedAuthority(a.getAuthority()));
                        });
                    });
                    myCredentials.setAuthorityEntities(authorityEntities);
                    myCredentials.setAuthorities(as);

                    //获取当前认证信息
                    myCredentials.setAccount(user);

                    user.setRoleEntities(null);
                    user.setPassword(null);

                    UserEntity userEntity = userService.getByAccountId(user.getId());
                    myCredentials.setUser(userEntity);

                    SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user.getUsername(),
                            myCredentials,
                            grantedAuthorities));

                    httpServletResponse.setStatus(HttpStatus.OK.value());
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.ok("认证成功", myCredentials)));
                } catch (Exception e) {
                    e.printStackTrace();
                    httpServletResponse.setStatus(HttpStatus.OK.value());
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.error("认证失败,未知异常")));
                }
            } else {

                if (httpServletRequest.getRequestURI().equals("/myAuthentication")) {
                    HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
                    httpServletResponse.setStatus(HttpStatus.OK.value());
                    httpServletResponse.setContentType("application/json;charset=utf-8");

                    SecurityContext context = SecurityContextHolder.getContext();

                    if (context == null) {
                        httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.ok()));
                    } else {
                        Authentication authentication = context.getAuthentication();
                        if (authentication == null) {
                            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.ok()));
                        } else {
                            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.ok(authentication.getCredentials())));
                        }
                    }


                } else {
                    filterChain.doFilter(servletRequest, servletResponse);
                }

            }


        }, UsernamePasswordAuthenticationFilter.class);


        http.cors().disable();
        http.csrf().disable();
        http.authorizeRequests()
                .antMatchers("/loopOrder/passApplyForActiveTaxCategoriesAndCycle/**").permitAll()
                .antMatchers("/", "/font/**").permitAll()
                .antMatchers("/swagger-ui.html/**", "/webjars/**", "/swagger-resources/**", "/v2/api-docs/**")
                .permitAll()
                .anyRequest().authenticated();

        //拦截
        http.exceptionHandling().accessDeniedHandler((httpServletRequest, httpServletResponse, e) -> {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.unauthorized("未登录")));
        }).authenticationEntryPoint((httpServletRequest, httpServletResponse, e) -> {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.getWriter().write(objectMapper.writeValueAsString(R.forbidden("无权访问")));
        });

    }


    @Override
    public void afterPropertiesSet() throws Exception {
        AccountEntity superadmin = accountService.loadUserByUsername("superadmin");
        if (superadmin == null) {
            System.err.println("超级管理员用户不存在，项目无法启动");
            System.exit(1);
        }

        if (superadmin.getPassword() == null) {
            String super_admin_password = configPropertyService.getConfig("super_admin_password");
            if (super_admin_password == null) {
                super_admin_password = "123456";
                configPropertyService.setConfig("super_admin_password", super_admin_password, "超级管理员初始密码");
            }
            accountService.setPassword(superadmin.getUsername(), super_admin_password);
        }
    }


}
